#include "GSMv3.h"


#define PIN_GSM_PWR   PIN_C5                                                        //power ON pin
#define LED1		  PIN_A5                                                        //need to be set
#define LED2		  PIN_A4
#define LED3		  PIN_C4														//LED 3 is in interface board
#define UP_BTN		  PIN_B5
#define DW_BTN		  PIN_B6
#define RS_BTN		  PIN_B4
#define NUM_QUE {4,6,8,14,16,18,24,26,28,34,36,38,44,46,48,54,56,58,0}	  			//***make sure the last number is zero
#define LOC_ST		  "TST01"														//location string to identify unit when sending status updates

//#define DEBUG  ////**** comment this line when compiling for a release
#define NUM_RSV ////Enable Number reservation code

//////////////////// Funtion Prototypes /////////////////////////////////////
void gsm_init(short state);         //power up the gsm module
void gsm_reg();
void sendmsg( char msg[], char num[]);
char* get_string(char dest[] , int len);
void check_sms();
void delete_sms(char sms_index_st[]);
void delay_with_pin(int time);
void inc_bcd();
void dec_bcd();
char eeprom_valid_read(char loc);
void eeprom_valid_write(char loc, char val);
char init_eeprom();															//returns the valid eeprom base address for this session
char get_resv_num();
char get_nxt_loc(char loc);													   //get next eeprom location to read or write from (skip any locations from 0 -3)
void do_gprs(char i, char j, char k);
////////////////////////////////////////////////////////////////////////////

////////////////// Global Variables ////////////////////////////////////////
volatile short reg = FALSE;                                                          // properly registered in operator network
volatile short valid_sms = FALSE;													//filters out service SMSs which doesn't have a sender number
volatile char sms_index_st [2] = "";													//index number of the sms currently handled, required for deleting that sms, after reply is sent
volatile short new_sms = FALSE;														// TRUE if there are any new SMSs as indicated by the response to CMGL
volatile char reply_num [12]="";
volatile short c_rdy_flag = FALSE;
volatile short cnt_ok_flag = FALSE;
volatile short snd_ok_flag = FALSE;
char sms_count = 0;															//number of SMS replied to, for record keeping
char res_count = 0;														    //number of reservations made
char p_num = 0;  															//Current Patient Number
char p_num_s [3]="00";
char res_num_s [3] = "00";
char tcount = 10;															//required in RX ISR
char sms_count_string [3]= "00";
char cat_msg [50] = "";
char sms_msg [4]  = "";
char num_msg [4]   = "num";
char res_msg [4]   = "res";
char num_index = 0;															//index of the number reservation array
char new_address = 0;														//base EEPROM address for this session
short ee_err = FALSE;														//if true, an error has occured in reading EEPROM base address
char cmgl [6] = "+CMGL";
short doing_gprs = FALSE;
char C_RDY [] = "+CCALR:1";
char CNT_OK [] = "CONNECT OK";
char SND_OK [] = "SEND OK";

const char num_array[] = NUM_QUE ;

const char nw_srv_msg [14] = " Now :";
const char num_resv_msg [18] = "Number Reserved :";
const char hlp_msg [] = "Please send NUM or RES"; 
const char que_end_msg [] = "Sorry, Numbers finished";
const char eeprom_err [] = "EE ERR";
char home_num [13]= "+94714457393"; //"+94716296626";  //"+94713924252"; 

////////////////////////////////////////////////////////////////////////////

#int_rda
void serial_isr() {
		
    char rx_st1 [40];
	char i=8;																						//used to find the "+" in the CMGL string

	if(doing_gprs)	{
		while(kbhit()) getc(); 
	}

	else	{

	get_string(rx_st1,40);
                                        									 // +CMGL
 	   if(strncmp((rx_st1),cmgl,5)== 0)	{
 
		  output_bit(LED2,1);      
		  new_sms = TRUE;	
	  
		  sms_index_st[0] = rx_st1[7];
		  sms_index_st[1] = '0';

		  if(isdigit(rx_st1[8]))	{																		//if the SMS index is >9, needs special processing.. 
				sms_index_st[1] = rx_st1[7];																//..to record both digits of the index number
				sms_index_st[0] = rx_st1[8];
		 }

		  valid_sms = FALSE;
  		  while (TRUE)   {
	      	i++;
	      	if(rx_st1[i] == 43) { valid_sms = TRUE; break;}                                                //find the "+"
			if(i > 35) break;																			   // no + found, SMS not valid. proceed to delete 
	      	}

	      reply_num[0] = 43;
	      reply_num[1] = rx_st1[i+1];
	      reply_num[2] = rx_st1[i+2];
	      reply_num[3] = rx_st1[i+3];
	      reply_num[4] = rx_st1[i+4];
	      reply_num[5] = rx_st1[i+5];
	      reply_num[6] = rx_st1[i+6];
	      reply_num[7] = rx_st1[i+7];
	      reply_num[8] = rx_st1[i+8];
	      reply_num[9] = rx_st1[i+9];
	      reply_num[10] = rx_st1[i+10];
	      reply_num[11] = rx_st1[i+11];
		  get_string(sms_msg,3);
		  sms_msg[3] = 0;
      }   

 	 else if (rx_st1[3] == 'E' && rx_st1[9] == '1' ) {                           // +CREG: 0,1
  		 reg = TRUE;
		
	}
	else if (strncmp((rx_st1),C_RDY,8)== 0 )	{
		c_rdy_flag = TRUE;															//string Call Ready received from GSM module
	}
	else if (strncmp((rx_st1),CNT_OK,10)== 0)	{
		cnt_ok_flag = TRUE;															//string CONNECT OK from GSM module
	}
	else if (strncmp((rx_st1),SND_OK,7)== 0)	{
		snd_ok_flag = TRUE;
	}
	tcount = 2;																	//refreshing tcount to see if more lines are to be received
	}				//end of else
}


void main()	{
   
char address = 0;     
char resv_num = 0;

#ifndef DEBUG
	delay_ms(1000);
#endif
	
	output_bit(LED3,1);
//	delay_ms(1000);
//	output_bit(LED3,0);
	
//to start with address should be 4 and value should be 0, first 4 eeprom locations should be set to number 4 at the very first start.
//and eeprom(4), (5),(6) should be set to zero(sms_count) and eeprom(7) (8) (9) should be zero (patient number) and (10) (11) (12) should also be set to zero (number reserve array index)
//and locations 13,14,15 should also be set to zero (res_count)
   address = init_eeprom();
   if (address == 0) {
		ee_err = TRUE;
		address = 4;											//if address error occured, revert to initial base address, all previous information will be lost.
	}

   new_address = address + 3;
   if(new_address<4) new_address = 4;							//skip the first 4 locations in which the value of the address is stored

   write_eeprom(0,new_address);	write_eeprom(1,new_address); write_eeprom(2,new_address); write_eeprom(3,new_address); 						//write new address to locations 0,1,2,3
                 					

    sms_count = eeprom_valid_read(address);
    p_num = eeprom_valid_read(address+3);
	num_index = eeprom_valid_read(address+6);
	res_count = eeprom_valid_read(address+9);					//*


#ifndef DEBUG
	delay_ms(1000);
	setup_uart(0);
	gsm_init(1);
	delay_ms(1000);
#endif
	
	clear_interrupt(int_rda);
	enable_interrupts(int_rda);
	enable_interrupts(global);

#ifndef DEBUG
	delay_ms(1000);
	setup_uart(1);
	output_bit(LED1,1);
	delay_ms(1000);
	gsm_reg();
	output_bit(LED1,0);

	output_bit(LED1,1);
#endif

	delay_ms(1000);


	p_num_s[1] = (p_num & 0b00001111)+48;						// convert Previous days patient number in to string
	p_num_s[0] = ((p_num & 0b11110000)/16)+48;

	eeprom_valid_write(new_address, 0);							// reset sms count for the next run (this is required incase we do not send any sms in this run)
	eeprom_valid_write(new_address+3, p_num);
	eeprom_valid_write(new_address+6, num_index);	
    eeprom_valid_write(new_address+9, res_count);

    sendmsg(p_num_s , home_num);                               //sending status message, sms count is sent by default if number==home_num, here additionally we are sending the patient count of previous day as well.


//////**********need to write res_count and num_index to new eeprom locations ( this is required incase we don't reserve any numbers this session///
//////**********also set num_index eeprom to zero in the reset 

	delay_ms(1000);
	do_gprs(sms_count,num_index,res_count);
 	res_count = 0;
	sms_count = 0;												// reset sms count for the next run

/*	if(ee_err) {												//if eeprom address error has occured, send a warning message.
		strcpy(cat_msg,eeprom_err );
		sendmsg(cat_msg, home_num);	
	}*/

#ifndef DEBUG
    delay_ms(4000);
#endif

 while(TRUE)  {																		//main loop, this is were everything happens, runns at approx 1Hz
	tcount = 2;
	output_bit(LED1,0);output_bit(LED2,0);
	check_sms();
	
	while(tcount>0)	{																//allow time after each received line to see if any more data is on the way
		delay_with_pin(10);															//tcount is refreshed each time rx ISR is called
		tcount--;
	}

	delay_with_pin(10); 															//allowing time for the GSM module to respond with all received text messages
	output_bit(LED1,1);

	if(new_sms)		  {
         if(valid_sms && (reply_num[4] == '1')) { 									//check for Mobitel messages

///////////////// This section is inlcuded only if Number reservation functionality is required ////////////////
#ifdef NUM_RSV 
			 strlwr(sms_msg);
  		 	 if((strncmp((sms_msg),num_msg,3)== 0) )	{
				 strcpy(cat_msg,nw_srv_msg);
				 strcat(cat_msg, p_num_s);						//current number message
			 	}
 
			 else if((strncmp((sms_msg),res_msg,3)== 0) )	{
				 resv_num = get_resv_num();
				 if (resv_num != 0) 	{
				 	strcpy(cat_msg,num_resv_msg);
				 	itoa(resv_num,10,res_num_s);
				 	strcat(cat_msg, res_num_s);					// reserved number message
				    }
				 else strcpy(cat_msg,que_end_msg);				//all numbers reserved,
				}
			 else strcpy(cat_msg,hlp_msg);						// help message*****

#else    //if Number reservation feature is not required, don't need to compare stings, simply send the number
			 strcpy(cat_msg,nw_srv_msg);
			 strcat(cat_msg, p_num_s);						//current number message			

#endif	
//////////////////////////////////////////////////////////////////////////////////////////////////
		
			 sms_count++;  
			 eeprom_valid_write(new_address, sms_count);							
			
			 sendmsg(cat_msg, reply_num);

#ifndef DEBUG
			 delay_with_pin(20);
#else
			delay_with_pin(2);
#endif
		 }

         delete_sms(sms_index_st);
		 output_bit(LED2,0);
		 new_sms = FALSE; 
       }

#ifndef DEBUG	
	delay_with_pin(20);
#else
	delay_with_pin(2);
#endif	
	}
}

                                                     
void gsm_init(short state)   {

 if (state)   {                                                                 //switch on
    output_bit(PIN_GSM_PWR, 0);
    delay_ms(1000);
    output_bit(PIN_GSM_PWR, 1);
    delay_ms(2000);
    output_bit(PIN_GSM_PWR, 0);//

    delay_ms(10000);                                                            //wait till network registration

  }
}


void gsm_reg()   {

char reg_chk_cmd[9] = "at+creg?";
char call_rdy_chk_cmd[]= "at+ccalr?";
char attempts = 0;

while(!c_rdy_flag && attempts++ < 10)   {
        puts(call_rdy_chk_cmd);
		delay_ms(5000);
      }
attempts = 0;

while(!reg && attempts++ < 5)   {
		puts(reg_chk_cmd);
		delay_ms(3000);
      }
//	delay_ms(3000);
}


char* get_string(char dest[] , int len) {
char i,c;
i=0;

   while(TRUE) {
      c=getc();

      if(i<len) dest[i]= c;
      if (c==10) break;
      i++;
   }
   return dest;
}

void sendmsg(char msg[],char num[])   {

   disable_interrupts(global);                                                  //when sending do not bother about other interrupts
		
//////////////////////
    putc('a');    putc('t');    putc('+');    putc('c');    putc('m');    putc('g');    putc('s');
    putc('=');
    putc('"');
    putc(num[0]);    putc(num[1]);    putc(num[2]);    putc(num[3]);    putc(num[4]);    putc(num[5]);
    putc(num[6]);    putc(num[7]);    putc(num[8]);    putc(num[9]);    putc(num[10]);    putc(num[11]);
    putc('"');
    putc(13);
////////////////////////

   while(!kbhit());                                                             //wait for input
   while(getc() != 32);                                                         //if input char is 'space' then proceed to sending msg txt
   puts(msg);
                                       
   if(strncmp(home_num,num,12)== 0 )	{										//if home num, then send sms_count as well
		itoa(sms_count, 10, sms_count_string);
		putc(10); printf(sms_count_string);
	}

   putc(10); printf("Thank you for using TexMed Service\n\r");
   putc(26);																	//ctrl+z
   enable_interrupts(global);
   
  }

void check_sms()   {

    putc('a');    putc('t');    putc('+');    putc('c');    putc('m');    putc('g');    putc('l');
    putc('=');    putc('"');
    putc('a');    putc('l');    putc('l');
    putc('"');
    putc(13);
    delay_ms(500);
}

void delete_sms(char sms_index_st[])   {

    putc('a');    putc('t');    putc('+');    putc('c');    putc('m');    putc('g');    putc('d');
    putc('=');    putc(sms_index_st[1]);  putc(sms_index_st[0]);
    putc(13);
	
}

void delay_with_pin(int time)	{

	int i =0;
	for(i=0; i<=time; i++)	{
	if(input(UP_BTN)) { while(input(UP_BTN)); inc_bcd();}
    if(input(DW_BTN)) { while(input(DW_BTN)); dec_bcd();}
//	if(input(RS_BTN)) { while(input(RS_BTN)); p_num = 0;}
	if(input(RS_BTN)) { 
		delay_ms(2000);
		if(input(RS_BTN)) {
			while(input(RS_BTN))
		    p_num = 0; 
		    num_index =0;
		}
	}

	output_bit(PIN_B0,bit_test(p_num,4));
	output_bit(PIN_B1,bit_test(p_num,5));
	output_bit(PIN_B2,bit_test(p_num,6));
	output_bit(PIN_B3,bit_test(p_num,7));

	output_bit(PIN_A0,bit_test(p_num,0));
	output_bit(PIN_A1,bit_test(p_num,1));
	output_bit(PIN_A2,bit_test(p_num,2));
	output_bit(PIN_A3,bit_test(p_num,3));


	p_num_s[1] = (p_num & 0b00001111)+48;
	p_num_s[0] = ((p_num & 0b11110000)/16)+48;

#ifndef DEBUG	
	delay_ms(100);
#endif
										
#ifdef DEBUG
	delay_ms(1);
#endif

	} 
}

void inc_bcd()   {
char digit1 = 0;
char digit2 = 0;

digit1 = p_num & 0b00001111;
digit2 = p_num & 0b11110000;

if(digit1 == 9) {
    if(digit2 == 144) p_num = 0;              							//10010000 = 144
    else p_num=(p_num+7); 											
   }

else p_num++;
eeprom_valid_write(new_address+3, p_num);
}

void dec_bcd()   {
char digit1 = 0;
char digit2 = 0;

digit1 = p_num & 0b00001111;
digit2 = p_num & 0b11110000;

if(digit1 == 0) {
   if(digit2==0) p_num = 0;
   else p_num=p_num-7;
   }

else p_num--;
eeprom_valid_write(new_address+3, p_num);
}


char init_eeprom()			{
   char store_1 = 0;
   char store_2 = 0;
   char store_3 = 0;
   char store_4 = 0;
   char val = 0;

   disable_interrupts(global);  

   store_1 = read_eeprom(0);
   store_2 = read_eeprom(1);
   store_3 = read_eeprom(2);
   store_4 = read_eeprom(3);


   if (store_1 == store_2) 				val = store_1;
   else if (store_2 == store_3) 		val = store_2;				    //corruption occured when writing to 1st location
   else if   (store_3 == (store_4))	    val = store_3;					//corruption occured when writing to 2nd location
   else val = 0;                              							//something's really wrong!!!

   enable_interrupts(global);
    return val;
//	return store_1;

}


char eeprom_valid_read(char loc)   {
   char store_1 = 0;
   char store_2 = 0;
   char store_3 = 0;
   char val = 0;

   disable_interrupts(global);  

   store_1 = read_eeprom(get_nxt_loc(loc));
   store_2 = read_eeprom(get_nxt_loc(loc+1));
   store_3 = read_eeprom(get_nxt_loc(loc+2));

   if (store_1 == store_2) 				val = store_1;
   else if (store_2 == store_3) 		val = store_2 + 1;				//corruption occured when writing to 1st location
   else if   (store_1 == (store_3+1))	val = store_1;					//corruption occured when writing to 2nd location
   else val = 0;                              							//more than 1 value corrupted

   enable_interrupts(global);
   return val;
}

void eeprom_valid_write(char loc, char val)      {

	write_eeprom(get_nxt_loc(loc),val);
	write_eeprom(get_nxt_loc(loc+1),val);
	write_eeprom(get_nxt_loc(loc+2),val);
}

char get_nxt_loc(char loc)	{											//to prevent from writing to first four memory locations
	if (loc < 4)	loc = 4;
	return loc;
}


char get_resv_num()			{
	char current_num;
	res_count++;									//*
	current_num = ((p_num<<4)>>4) + (p_num>>4)*10; 

	if (num_array[num_index] != 0) num_index++;

	while	( (num_array[num_index] != 0) && (num_array[num_index] < (current_num+10)) ) num_index++;
	
	eeprom_valid_write(new_address+6, num_index);
	delay_ms(500);
	eeprom_valid_write(new_address+9, res_count); //*
	delay_ms(500);
	return num_array[num_index];
}


void do_gprs(char i, char j, char k)	{
	
	char attempts = 0;
	doing_gprs = FALSE;
	cnt_ok_flag = FALSE;

	printf("AT+CDNSORIP=1\r\n");
	delay_ms(500);
	printf("AT+CIPMUX=0\r\n");
	delay_ms(500);
	printf("AT+CIPMODE=0\r\n");
	printf("AT+CIPCSGP=1,\"mobitel3g\"\r\n");
	printf("AT+CLPORT=\"TCP\",\"2020\"\r\n");
	printf("AT+CSTT=\"mobitel3g\",\"\",\"\"\r\n");
	printf("AT+CIPSRIP=1\r\n");
	delay_ms(1000);
	printf("AT+CIICR\r\n");
	delay_ms(1000);
	printf("AT+CIFSR\r\n");
	delay_ms(1000);
	printf("AT+CIPSTART=\"TCP\",\"spreadsheets.google.com\",\"80\"\r\n");

	while(!cnt_ok_flag && attempts++ < 10) {	//cnt_ok_flag is set in ISR if CONNECT OK string is received
		delay_ms(1000);
	}
	if(!cnt_ok_flag) return;				//if still not connected, then forget gprs and proceed

	doing_gprs = TRUE;					//response to CIPSEND doesn't include a linefeed. Therefore, if we request a new line by using get_string(), it doesn't return. Keeping the response checking in the UART ISR disable for that reason
	printf("AT+CIPSEND\r");
	delay_ms(2000);
	printf("POST /spreadsheet/formResponse?"); 	
	printf("formkey=dHEtR05ia2FvUEg4WUM3UWt3XzNlb0E6MQ&ifq HTTP/1.1\r\n" );			//new form
	printf("Content-Type:application/x-www-form-urlencoded\r\n");
	printf("Host: spreadsheets.google.com\r\n");
	printf("Content-Length:112\r\n");
	printf("\r\n");
	printf("entry.0.single=%u&entry.1.single=%u&entry.2.single=%u&entry.3.single=%s&",i,j,k,LOC_ST);printf("pageNumber=0&backupCache=&submit=Submit");
	printf("\r\n");
	putc(26);
	doing_gprs = FALSE;						//enabling responsing checking in the UART ISR because we need to detect SEND OK response
	attempts = 0;
    while(!snd_ok_flag && attempts++ < 20)	{                                                             //wait for input
		delay_ms(500);
	}

	doing_gprs = TRUE;
//	delay_ms(100);
	printf("AT+CIPSHUT\r\n");
	delay_ms(1000);
	doing_gprs = FALSE;

}
